using System;
using System.Collections.Generic;
using System.Text;

namespace HW2and3
{
    class KTStateKnight : StateInterface, ICloneable, IComparable
    {
        public short[,] board;
        private int x;
        private int y;
        private static short index = 1;
        private static int[] vertical = { -1, -2, -2, -1, 1, 2, 2, 1 };
        private static int[] horizontal = { 2, 1, -1, -2, -2, -1, 1, 2 };
        private int nextBestAccesibility;
        private int secondNextBestAccesibility;
        private bool isLookAheadState;

        public KTStateKnight(int size, int x, int y, bool isLookAheadState)
        {
            index = 1;
            board = new short[size, size];
            this.x = x;
            this.y = y;
            board[this.x,this.y] = index;
            this.isLookAheadState = isLookAheadState;
            if (isLookAheadState)
                CalculateNextBestAccesibility();
        }

        public KTStateKnight(int x, int y, bool isLookAheadState)
        {
            this.x = x;
            this.y = y;
            this.isLookAheadState = isLookAheadState;
        }

        private void SetCoordinates(int x, int y)
        {
            board[x, y] = ++index;
            this.x = x;
            this.y = y;
            if (isLookAheadState) CalculateNextBestAccesibility();
        }

        private void CalculateNextBestAccesibility()
        {
            int max = -1;
            int xi = 0;
            int yi = 0;
            for (int i = 0; i < horizontal.Length; i++)
            {
                int a = this.X + vertical[i];
                int b = this.Y + horizontal[i];
                if (a >= 0 && a < this.Board.GetLength(0) && b >= 0 && b < this.Board.GetLength(0) && this.Board[a, b] == 0)
                {
                    if (max < KTModelDFSLookAhead.accesibility[a, b])
                    {
                        max = (int)KTModelDFSLookAhead.accesibility[a, b];
                        xi = a;
                        yi = b;
                    }
                }
            }
            nextBestAccesibility = max;
            CalculateSecondNextBestAccesibility(xi, yi);
        }

        private void CalculateSecondNextBestAccesibility(int x, int y)
        {
            int max = -1;

            for (int i = 0; i < horizontal.Length; i++)
            {
                int a = x + vertical[i];
                int b = y + horizontal[i];
                if (a >= 0 && a < this.Board.GetLength(0) && b >= 0 && b < this.Board.GetLength(0) && this.Board[a, b] == 0)
                {
                    if (max < KTModelDFSLookAhead.accesibility[a, b])
                        max = (int)KTModelDFSLookAhead.accesibility[a, b];
                }
            }
            secondNextBestAccesibility = max;
        }

        public short[,] Board
        {
            get { return board; }
        }

        public int LastX
        {
            get { return x; }
        }

        public int LastY
        {
            get { return y; }
        }

        public short Index
        {
            get { return index; }
            set { index = value; }
        }

        public int X
        {
            get { return x; }
            set { x = value; }
        }

        public int Y
        {
            get { return y; }
            set { y = value; }
        }

        public int NextBestAccesibility
        {
            get { return nextBestAccesibility; }
            set { nextBestAccesibility = value; }
        }

        public int SecondNextBestAccesibility
        {
            get { return secondNextBestAccesibility; }
        }

        public KTStateKnight GetNewState(int x, int y)
        {
            KTStateKnight tmp = (KTStateKnight)this.Clone();
            tmp.SetCoordinates(x, y);
            return tmp;
        }

        public KTStateKnight GetNewState(int x, int y, int value)
        {
            KTStateKnight tmp = (KTStateKnight)this.Clone();
            tmp.SetCoordinates(x, y, value);
            return tmp;
        }

        public void SetCoordinates(int x, int y, int value)
        {
            board[x, y] = (short)value;
            this.x = x;
            this.y = y;
            if (isLookAheadState) CalculateNextBestAccesibility();
        }

        public object Clone()
        {
            KTStateKnight tmp = new KTStateKnight(this.x, this.y, this.isLookAheadState);

            tmp.board = (short[,])(this.board.Clone());
            //tmp.board[this.x, this.y] = 1;
            return (object)tmp;
        }

        public int CompareTo(object obj)
        {
            if (obj is KTStateKnight)
            {
                KTStateKnight tmp = (KTStateKnight)obj;
                int accesibility1 = KTModelDFSLookAhead.accesibility[this.X, this.Y];
                int accesibility2 = KTModelDFSLookAhead.accesibility[tmp.X, tmp.Y];
                if (accesibility1 != accesibility2)
                    return accesibility1 - accesibility2;
                else if (this.NextBestAccesibility != tmp.NextBestAccesibility)
                    return this.NextBestAccesibility - tmp.NextBestAccesibility;
                else
                    return this.SecondNextBestAccesibility - tmp.SecondNextBestAccesibility;
            }
            throw new ArgumentException("Object is not KTStateKnight");
        }
    }
}
